/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.core.session;

import com.inspur.edp.bef.core.session.distributed.close.AbnormalClosingUtil;
import com.inspur.edp.commonmodel.core.session.serviceinterface.SessionConfigService;
import com.inspur.edp.commonmodel.core.session.tableentity.SessionCacheInfo;
import com.inspur.edp.commonmodel.core.session.tableentity.SessionConfig;
import com.inspur.edp.commonmodel.core.util.SessionIncrementUtil;
import io.iec.edp.caf.boot.context.CAFContext;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.core.context.BizContextManager;
import io.iec.edp.caf.core.context.ICAFContextService;
import io.iec.edp.caf.core.session.CafSession;
import io.iec.edp.caf.core.session.ICafSessionService;
import io.iec.edp.caf.core.session.SessionType;
import io.iec.edp.caf.core.session.core.CAFSessionThreadHolder;
import io.iec.edp.caf.msu.api.ServiceUnitAwareService;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.security.core.context.SecurityContextHolder;

@Slf4j
@DisallowConcurrentExecution
public class SessionValidityCheck implements Job {

  private static HashMap<String, List<Date>> dates = new HashMap<>();
  private static HashMap<String, List<String>> linkInfoRecord = new HashMap<>();

  @Override
  public void execute(JobExecutionContext arg0) throws JobExecutionException {
    try {
      cleanExpiredFuncSession();
      cleanByLocalCache();
      //traversalCleanByDB();
      //cleanByBizContext();
    } catch (Throwable r) {
      log.error("定时任务执行失败", r);
    }
  }

//  private static void cleanByBizContext() {
//    ConcurrentHashMap<String, List<String>> tokenBefBizContext = FuncSessionManager
//        .getTokenBefBizContextId();
//    BizContextManager bizContextManager = SpringBeanUtils.getBean(BizContextManager.class);
//
//    for (Map.Entry<String, List<String>> token : tokenBefBizContext.entrySet()) {
//      try {
//        if (token.getValue() == null) {
//          continue;
//        }
//        synchronized (token.getValue()) {
//          Iterator iterator = token.getValue().iterator();
//          iterator.next();
//          while (iterator.hasNext()) {
//            String befBizContextId = (String) iterator.next();
//            if (!bizContextManager.isExpired(befBizContextId)) {
//              continue;
//            }
////                  bizContextManager.destroy(befBizContextId);
//            if (FuncSessionManager.getCurrent().getSession(befBizContextId) != null) {
//              FuncSessionManager.getCurrent().closeSessionWithDestroy(befBizContextId);
//            }
//            iterator.remove();
//          }
//          if (token.getValue().isEmpty() || (token.getValue().size() == 1 && (
//              token.getValue().get(0) == null || token.getValue().get(0).length() != 36))) {
//            tokenBefBizContext.remove(token.getKey());
//          }
//        }
//      } catch (BizContextNotFoundException | BizContextDestroyFailedException e) {
//        if (e instanceof BizContextNotFoundException) {
//          throw new CAFRuntimeException("", ErrorCodes.Scope_BizContextNotFound,
//              e.getMessage(), e, ExceptionLevel.Error);
//        }
//        if (e instanceof BizContextDestroyFailedException) {
//          throw new CAFRuntimeException("", ErrorCodes.Scope_BizContextDestroyFailed,
//              e.getMessage(), e, ExceptionLevel.Error);
//        }
//      }
//    }
//  }

  private static synchronized void cleanExpiredFuncSession() {
    try {
      LocalDateTime timeThreshold = LocalDateTime.now().minusMinutes(15);
      BizContextManager bizContextManager = SpringBeanUtils.getBean(BizContextManager.class);
      for (Map<String, FuncSession> sessionMap : FuncSessionManager.getCurrent().getBuckets()
          .values()) {
        if (sessionMap == null || sessionMap.isEmpty()) {
          continue;
        }
        List<String> expiredIds = new ArrayList<>();
        Iterator<Map.Entry<String, FuncSession>> iterator = sessionMap.entrySet().iterator();
        while (iterator.hasNext()) {
          try {
            Map.Entry<String, FuncSession> item = iterator.next();
            if (item.getValue().isExpired()) {
              expiredIds.add(item.getKey());
            } else if (item.getValue().getLastOn().isBefore(timeThreshold) && bizContextManager
                .isExpired(item.getKey())) {
              expiredIds.add(item.getKey());
            }
          }catch(Throwable t) {
            log.error("cleanExpiredFuncSession failed 1", t);
          }
        }
        if (!expiredIds.isEmpty()) {
          for (String item : expiredIds) {
            FuncSessionManager.getCurrent().closeSessionWithDestroy(item);
          }
        }
      }
    } catch (Throwable r) {
      log.error("cleanExpiredFuncSession failed 9", r);
    }
  }

  private static synchronized void cleanByLocalCache() {
    try {
      AbnormalClosingUtil util = new AbnormalClosingUtil();
      List<String> tokenIds = util.getValidityTokenId();
      if (tokenIds == null || tokenIds.isEmpty()) {
        return;
      }
      int failedCount = 0;
      Throwable lastError = null;
      for (String tokenId : tokenIds) {
        try {
          List<String> sessionIds = util.clearLocalCache(tokenId);
//          util.clearLocalCache(tokenId);
          if (sessionIds == null || sessionIds.isEmpty()) {
            continue;
          }
          for (String item : sessionIds) {
            FuncSessionManager.getCurrent()
                .closeSessionWithDestroy(FuncSessionUtil.getSessionIdBySplit(item));
          }
        } catch (Throwable t) {
          failedCount++;
          lastError = t;
        }
      }
      if (failedCount > 0) {
        log.error("cleanExpiredFuncSession定时任务内部失败次数" + failedCount, lastError);
      }
    } catch (Throwable r) {
      log.error("cleanExpiredFuncSession定时任务执行失败", r);
    }
  }

//  public void traversalCleanBySU() {
//
//    SessionConfigService service = SpringBeanUtils.getBean(SessionConfigService.class);
//    List<SessionConfig> configs = service.getAllConfig();
//    List<String> deployedSu = SpringBeanUtils.getBean(ServiceUnitAwareService.class)
//        .getEnabledServiceUnits();
//    if (configs == null || configs.size() == 0 || deployedSu == null || deployedSu.size() == 0) {
//      return;
//    }
//    List<String> specialTenantId = new ArrayList<>();
//
//    if (linkInfoRecord.size() == 0) {
//      for (SessionConfig config : configs) {
//        if (!config.getConnectInfo().isUseCache() ||
//            !deployedSu.contains(config.getBelongSU()) && !"*".equals(config.getBelongSU()) ||
//            specialTenantId.contains(config.getBelongTenant())) {
//          continue;
//        }
//        if ("*".equals(config.getBelongSU())) {
//          linkInfoRecord.put(config.getBelongTenant(), deployedSu);
//          specialTenantId.add(config.getBelongTenant());
//          continue;
//        }
//        if (!linkInfoRecord.containsKey(config.getBelongTenant())) {
//          ArrayList<String> suCodes = new ArrayList<>();
//          suCodes.add(config.getBelongSU());
//          linkInfoRecord.put(config.getBelongTenant(), suCodes);
//        } else {
//          List<String> tem = linkInfoRecord.get(config.getBelongTenant());
//          tem.add(config.getBelongSU());
//          linkInfoRecord.replace(config.getBelongTenant(), tem);
//        }
//      }
//    }
//
//    ICafSessionService sessionService = SpringBeanUtils.getBean(ICafSessionService.class);
//    if (CAFContext.current.getCurrentSession() != null) {
//      clearSession();
//    }
//    try {
//      for (String tenantId : linkInfoRecord.keySet()) {
//        for (String suCode : linkInfoRecord.get(tenantId)) {
//          clearSession();
//          CafSession session = sessionService
//              .create(Integer.parseInt(tenantId), "admin", "zh-CHS", new HashMap<>(),
//                  SessionType.backend);
//          CAFSessionThreadHolder.setCurrentSession(session);
//          ICAFContextService contextService = SpringBeanUtils.getBean(ICAFContextService.class);
//          contextService.setCurrentSU(suCode);
//          traversalCleanByDB(tenantId + "." + suCode);
//        }
//      }
//    } finally {
//      clearSession();
//    }
//  }

//  private void clearSession() {
//    CAFSessionThreadHolder.purge();
//    SecurityContextHolder.clearContext();
//  }
//
//  private void traversalCleanByDB(String tempKey) {
//    List<Date> temDates;
//    if (dates.containsKey(tempKey)) {
//      temDates = dates.get(tempKey);
//    } else {
//      List<Date> date = new ArrayList<>();
//      dates.put(tempKey, date);
//      temDates = date;
//    }
//    SessionIncrementUtil sessionUtil = new SessionIncrementUtil();
//    if (!sessionUtil.isUseAvailabilityFeature()) {
//      return;
//    }
//    BizContextManager bizContextManager = SpringBeanUtils.getBean(BizContextManager.class);
//    int tableNumber = sessionUtil.getDBTableNumber();
//    if (temDates.size() == 0 || temDates.size() != tableNumber) {
//      temDates.clear();
//      for (int i = 0; i < tableNumber; i++) {
//        temDates.add(new Date(0));
//      }
//    }
//    List<List<String>> expiredIds = new ArrayList<>();
//    List<List<SessionCacheInfo>> infos = sessionUtil.traversalCache(temDates);
//    for (int i = 0; i < temDates.size(); i++) {
//      List<String> temExpiredIds = new ArrayList<>();
//      for (SessionCacheInfo info : infos.get(i)) {
//        String id = info.getSessionId();
//        if (!temExpiredIds.contains(id) &&
//            (bizContextManager.isExpired(id) || FuncSessionManager.getCurrent().getSession(id)
//                .isExpired())) {
//          temExpiredIds.add(id);
//        }
//      }
//      expiredIds.add(temExpiredIds);
//      if (infos.get(i).size() == 500) {
//        temDates.set(i, infos.get(i).get(infos.get(i).size() - 1).getCreatedOn());
//      } else {
//        temDates.set(i, new Date(0));
//      }
//    }
//    sessionUtil.batchClear(expiredIds);
//    dates.replace(tempKey, temDates);
//  }

}
